from boot import (QListWidget, Qt, Union, QWidget, GlobalWidgetConfig, SmoothScrollDelegate,
    Dict, GlobalWidget, Signal, QPixmapCache, QPixmap, AvatarWidget, QHBoxLayout, QVBoxLayout, QLabel, QListWidgetItem, QColor, QSize)
from boot import logger, FontFamily, List, QSizePolicy, CurrentSelectedID, ListWidgetObject
from utils.format import amount_format


__all__ = ["QQ9ListWidget", "QQ9ItemWidget", "QQ9TextWidget"]


class _QQ9ListWidgetBase(QListWidget):

    def __init__(self,
                    parent: Union[QWidget, None] = None,
                 ):
        super().__init__(parent=parent)

        # 基础设置
        self.setFixedWidth(GlobalWidgetConfig.list_widget_width)
        self.scrollDelegate = SmoothScrollDelegate(self)

        # 初始化隐藏滚动条
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        # 设置样式
        self._set_style_sheet()

    def _set_style_sheet(self):
        self.setStyleSheet(
            """
            QListWidget {
                border: none;
                border-right: 1px solid #EEF0F2;
                background-color: #FFFFFF;
                outline: none;
            }
            QListWidget::item:hover {
                background-color: #F5F6F7;
            }
            QListWidget::item:selected {
                background-color: #0099FF;
                color: transparent;
            }
            """
        )

    def enterEvent(self, event):
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

    def leaveEvent(self, event):
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)


class _QQ9ListWidgetItem(QListWidgetItem):

    def __init__(self,
                    parent: Union[QWidget, None] = None,
                    item_id: str = "",  # 项目id
                    item_widget: QWidget = None
                 ):
        super().__init__()
        # id编号
        self.id: str = item_id
        # 初始化字体颜色
        self.setForeground(QColor("#00000000"))
        # 设置尺寸
        self.setSizeHint(QSize(GlobalWidgetConfig.list_widget_width, 75))
        # 添加到list_widget中
        parent.addItem(self)
        # 将自定义item添加到列表中
        parent.setItemWidget(self, item_widget)


class QQ9ListWidget(_QQ9ListWidgetBase):

    def __init__(self,
                    parent: Union[QWidget, None] = None,
                    g_list_widget_name: str = "",  # 全局list_widget存储变量
                    g_current_selected_id_name: str = ""
                 ):
        super().__init__(parent=parent)

        # 注册自定义item_id对应的自定义item_widget
        self.item_widget_dict: Dict[str, QWidget] = {}
        # 注册ListWidget item对应的自定义item
        self.item_dict: Dict[str, QWidget] = {}
        # 上一次触发的item_id
        self.last_item_id: str = ""

        # 放入全局变量
        setattr(ListWidgetObject, g_list_widget_name, self)
        self.g_current_selected_id_name = g_current_selected_id_name

        # 窗口显示时调用一次头像刷新
        GlobalWidget.root.sgn_load_finished.connect(self.on_scroll)
        # 滑轮滚动时头像刷新
        # self.verticalScrollBar().valueChanged.connect(self.on_scroll)
        # 选择发生变化时触发
        try:
            self.itemSelectionChanged.connect(self.set_color_change)
            self.itemSelectionChanged.connect(self.set_current_selected_id)
        except IndexError:
            pass

    def on_scroll(self):
        """
        滑轮滚动时动态加载可见区域的头像，降低内存占用
        :return:
        """
        # 遍历所有item
        # try:
        #     for i in range(self.count()):
        #         item = self.item(i)
        #         item_widget = self.itemWidget(item)
        #         if self.is_item_visible(item):
        #             item_widget.set_avatar()
        # except AttributeError:
        #     logger.warning("滑轮操作过快")
        pass

    def _on_scroll(self):
        pass


    def is_item_visible(self, item: QListWidgetItem) -> bool:
        """
        判断某个 item 是否在可见区域内
        """
        rect = self.visualItemRect(item)
        return self.viewport().rect().intersects(rect)

    def add_item(self,
                 item_id: str = "",  # 项目id
                 icon_path: str = "",  # 项目图标路径
                 primary_name: str = "",  # 主名称
                 secondary_name: str = "",  # 副名称
                 back_name: str = "",  # 后名曾
                 show_back_name: bool = False,  # 是否显示后名曾
                 ) -> None:

        # 1. 创建ItemWidget
        item_widget = QQ9ItemWidget(
            item_id=item_id,
            icon_path=icon_path,
            primary_name=primary_name,
            secondary_name=secondary_name,
            back_name=back_name,
            show_back_name=show_back_name,
        )

        # 2. 创建 QListWidgetItem
        item = _QQ9ListWidgetItem(
            parent=self,
            item_id = item_id,
            item_widget=item_widget,
        )

        # 加入字典
        self.append_dict(item_id, item_widget, item)

    def append_dict(self,
                        item_id: str,
                        widget: QWidget,
                        item: QWidget,
                    ) -> None:
        self.item_widget_dict[item_id] = widget
        self.item_dict[item_id] = item

    def set_current_selected_id(self) -> None:
        try:
            self.selectedItems()[0].id
        except IndexError:
            return
        self.current_selected_id = self.selectedItems()[0].id

    @property
    def current_selected_id(self):
        return getattr(CurrentSelectedID, self.g_current_selected_id_name)

    @current_selected_id.setter
    def current_selected_id(self, item_id):
        setattr(CurrentSelectedID, self.g_current_selected_id_name, item_id)

    def set_color_change(self):
        """
        点击时颜色切换
        """
        try:
            item_id = self.selectedItems()[0].id
        except IndexError:
            item_id = None
        self._set_color_change(item_id)

    def _set_color_change(self, item_id):
        # 获取不到item_id时退出
        if item_id == self.last_item_id or item_id is None:
            return
        # 置位点击的item_widget颜色
        self.item_widget_dict[item_id].sgn_focus_in.emit()
        try:
            # 复位上次点击的item_widget颜色
            self.item_widget_dict[self.last_item_id].sgn_focus_out.emit()
        except KeyError:
            logger.warning(f"{self.last_item_id}颜色复位错误, 上次的item_id不存在")
        except RuntimeError:
            logger.warning(f"{self.last_item_id}复位错误")
        # 保存当前点击的item_id
        self.last_item_id = item_id

    def force_color_change(self, item_id):
        self.item_widget_dict[item_id].sgn_focus_in.emit()

    def _update(self, data_list: List[Dict], show_back_name:bool = False):
        # 1.清空list_widget
        self.clear()
        # 2.遍历列表数据
        for data in data_list:
            self.add_item(
                item_id=data["item_id"],
                icon_path=data["icon_path"],
                primary_name=data["primary_name"],
                secondary_name=data["secondary_name"],
                back_name=data["back_name"],
                show_back_name=show_back_name,
            )

    def edit_list_widget(self, data_list: List[Dict], show_back_name:bool = False):
        # 1.更新数据list_widget
        self._update(data_list, show_back_name)
        # 2.移动滑轮到当前编辑的位置
        self.scrollToItem(self.item_dict[self.current_selected_id])
        # 3.选择当前项目
        self.setCurrentItem(self.item_dict[self.current_selected_id])
        # 4.改变颜色
        self.force_color_change(self.current_selected_id)
        # 加载图片
        self.on_scroll()

    def refresh_list_widget(self, data_list: List[Dict], show_back_name:bool = False):
        # 1.刷新数据list_widget
        self._update(data_list, show_back_name)
        # 加载图片
        self.on_scroll()

    def delete_list_widget(self, data_list: List[Dict], show_back_name:bool = False):
        # 1.删除数据list_widget
        self._update(data_list, show_back_name)
        # 加载图片
        self.on_scroll()

    def add_list_widget(self, data_list: List[Dict], show_back_name:bool = False):
        # 1.新建数据list_widget
        self._update(data_list, show_back_name)
        # 2.移动滑轮到当前编辑的位置
        try:
            self.scrollToItem(self.item_dict[self.current_selected_id])
            # 3.选择当前项目
            self.setCurrentItem(self.item_dict[self.current_selected_id])
            # 4.改变颜色
            self.force_color_change(self.current_selected_id)
        except KeyError:
            logger.warning(f"{self.current_selected_id}，加载图片时，发现当前未筛选新加的项目，因此不在自动显示")
        # 加载图片
        self.on_scroll()


class QQ9ItemWidget(QWidget):

    # 触发点击事件
    sgn_clicked = Signal()
    # 鼠标点击获取焦点信号
    sgn_focus_in = Signal()
    # 鼠标移出获取焦点信号
    sgn_focus_out = Signal()

    def __init__(self,
                 parent: Union[QWidget, None] = None,
                 item_id: str = "",  # 项目id
                 icon_path: str = "",  # 项目图标路径
                 primary_name: str = "",  # 主名称
                 secondary_name: str = "",  # 副名称
                 back_name: str = "",  # 后名称
                 show_back_name: bool = False,  # 是否显示后名曾
                 ):
        super().__init__(parent=parent)

        self.item_id = item_id
        self.icon_path = icon_path

        # 主水平布局
        self.main_h_layout = QHBoxLayout()
        self.main_h_layout.setContentsMargins(20, 0, 0, 0)
        self.main_h_layout.setSpacing(5)
        self.setLayout(self.main_h_layout)

        # 初始化头像控件
        self.avatar = AvatarWidget()
        self.avatar.setRadius(21)
        self.main_h_layout.addWidget(self.avatar)

        # 初始化文本信息
        self.text_widget = QQ9TextWidget(
            primary_name=primary_name,
            secondary_name=secondary_name,
            back_name=back_name,
            show_back_name=show_back_name,
        )
        self.main_h_layout.addWidget(self.text_widget)

        # 信号绑定
        self.sgn_focus_in.connect(self.text_widget.parent_focus_in)
        self.sgn_focus_out.connect(self.text_widget.parent_focus_out)
        self.set_avatar()

    def set_avatar(self, icon_path: Union[str, None] = None):

        if icon_path is None:
            _icon_path = self.icon_path
        else:
            _icon_path = icon_path

        if _icon_path:
            # 1.检查 QPixmapCache 中是否已缓存
            pixmap = QPixmapCache.find(_icon_path)
            if not pixmap:
                # 2.如果未缓存，则加载并压缩图片
                pixmap = QPixmap(_icon_path)
                if not pixmap.isNull():
                    # 3.压缩图片到指定尺寸
                    compressed_pixmap = pixmap.scaled(42, 42, Qt.KeepAspectRatio, Qt.SmoothTransformation)
                    QPixmapCache.insert(_icon_path, compressed_pixmap)
                    pixmap = compressed_pixmap
            # 4.如果图片不为空，则设置到头像控件中
            if not pixmap.isNull():
                self.avatar.setPixmap(pixmap)

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        self.setFocus()
        self.text_widget.parent_focus_in()


class QQ9TextWidget(QWidget):

    def __init__(self,
                    parent: Union[QWidget, None] = None,
                    primary_name: str = "",  # 主名称
                    secondary_name: str = "",  # 副名称
                    back_name: str = "",  # 后名曾
                    show_back_name: bool = False,  # 是否显示后名曾
                 ):
        super().__init__(parent=parent)

        #初始化变量
        self.primary_name = primary_name
        self.secondary_name = secondary_name
        self.back_name = back_name
        self.show_back_name = show_back_name

        # 基础设置
        # 1.主布局
        self.main_h_layout = QHBoxLayout()
        self.main_h_layout.setContentsMargins(0, 0, 0, 0)
        self.main_h_layout.setSpacing(0)
        self.main_h_layout.setAlignment(Qt.AlignVCenter)
        self.setLayout(self.main_h_layout)
        # 2.前布局
        self.front_widget = QWidget()
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.front_widget.setContentsMargins(0, 0, 0, 0)
        self.front_v_layout = QVBoxLayout()
        self.front_v_layout.setContentsMargins(3, 15, 0, 15)
        self.front_v_layout.setAlignment(Qt.AlignHCenter | Qt.AlignLeft)
        self.front_widget.setLayout(self.front_v_layout)
        self.main_h_layout.addWidget(self.front_widget)

        self.primary_name_label = QLabel(self.primary_name)
        self.primary_name_label.setStyleSheet(
            """
            font-family: "微软雅黑";
            font-size: 14px;
            color: #111111;
            background-color: transparent;
            """
        )

        self.secondary_name_label = QLabel(self.secondary_name)
        self.secondary_name_label.setStyleSheet(
            f"""
            font-family: "微软雅黑";
            font-size: 12px;
            color: #919191;
            background-color: transparent;
            """
        )

        self.front_v_layout.addWidget(self.primary_name_label)
        self.front_v_layout.addWidget(self.secondary_name_label)

        # 3.后布局
        self.back_name_label = QLabel(amount_format(self.back_name))
        self.back_name_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.back_name_label.setContentsMargins(0, 0, 20, 0)
        self.back_name_label.setStyleSheet(
            f"""
            font-family: "{FontFamily.wechat_sans}";
            font-size: 15px;
            color: #ED464E;
            background-color: transparent;
            """
        )
        if self.show_back_name:
            self.main_h_layout.addWidget(self.back_name_label)

    def set_primary_name(self, primary_name: str):
        self.primary_name_label.setText(primary_name)

    def set_secondary_name(self, secondary_name: str):
        self.secondary_name_label.setText(secondary_name)

    def set_back_name(self, back_name: str):
        self.back_name_label.setText(amount_format(back_name))

    def parent_focus_in(self):
        self.primary_name_label.setStyleSheet(
            """
            font-family: "微软雅黑";
            font-size: 14px;
            color: #FFFFFF;
            background-color: transparent;
            """
        )
        self.secondary_name_label.setStyleSheet(
            f"""
            font-family: "微软雅黑";
            font-size: 12px;
            color: #FFFFFF;
            background-color: transparent;
            """
        )
        self.back_name_label.setStyleSheet(
            f"""
            font-family: "{FontFamily.wechat_sans}";
            font-size: 15px;
            color: #FFFFFF;
            background-color: transparent;
            """
        )

    def parent_focus_out(self):
        self.primary_name_label.setStyleSheet(
            """
            font-family: "微软雅黑";
            font-size: 14px;
            color: #111111;
            background-color: transparent;
            """
        )
        self.secondary_name_label.setStyleSheet(
            f"""
            font-family: "微软雅黑";
            font-size: 12px;
            color: #919191;
            background-color: transparent;
            """
        )
        self.back_name_label.setStyleSheet(
            f"""
            font-family: "{FontFamily.wechat_sans}";
            font-size: 15px;
            color: #ED464E;
            background-color: transparent;
            """
        )